#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/extensions/Xfixes.h>
#include <unistd.h>
#include <signal.h>

// 光标状态结构体
typedef struct {
    int x, y;              // 光标位置
    unsigned long cursor_id; // 光标ID（序列号）
    char* cursor_name;     // 光标名称
    int width, height;     // 光标尺寸
    int is_visible;        // 是否可见
} CursorStatus;

// 释放光标状态资源
void free_cursor_status(CursorStatus* status) {
    if (status) {
        if (status->cursor_name) {
            free(status->cursor_name);
        }
        free(status);
    }
}

// 方法1：基本的query_pointer获取光标信息
CursorStatus* get_cursor_status_basic(Display* display) {
    CursorStatus* status = malloc(sizeof(CursorStatus));
    if (!status) {
        fprintf(stderr, "内存分配失败\n");
        return NULL;
    }
    
    // 初始化
    memset(status, 0, sizeof(CursorStatus));
    status->cursor_name = strdup("未知");
    status->cursor_id = 0;
    
    Window root, child;
    int root_x, root_y, win_x, win_y;
    unsigned int mask;
    
    // 获取根窗口
    root = DefaultRootWindow(display);
    
    // 获取指针信息
    if (XQueryPointer(display, root, &root, &child, &root_x, &root_y, &win_x, &win_y, &mask)) {
        status->x = root_x;
        status->y = root_y;
        status->is_visible = 1;
        
        printf("基本方法: 位置=(%d,%d)\n", status->x, status->y);
    } else {
        fprintf(stderr, "基本方法: 无法获取指针信息\n");
        free_cursor_status(status);
        return NULL;
    }
    
    return status;
}

// 方法2：使用XFixes扩展获取光标信息
CursorStatus* get_cursor_status_xfixes(Display* display) {
    // 检查XFixes扩展是否可用
    int event_base, error_base;
    if (!XFixesQueryExtension(display, &event_base, &error_base)) {
        fprintf(stderr, "XFixes方法: XFixes扩展不可用\n");
        return NULL;
    }
    
    CursorStatus* status = malloc(sizeof(CursorStatus));
    if (!status) {
        fprintf(stderr, "内存分配失败\n");
        return NULL;
    }
    
    // 初始化
    memset(status, 0, sizeof(CursorStatus));
    status->cursor_name = strdup("未知");
    status->cursor_id = 0;
    
    // 获取光标图像信息
    XFixesCursorImage* cursor_image = XFixesGetCursorImage(display);
    if (cursor_image) {
        // 获取位置信息
        status->x = cursor_image->x;
        status->y = cursor_image->y;
        
        // 获取光标尺寸
        status->width = cursor_image->width;
        status->height = cursor_image->height;
        
        // 获取光标序列号（注意：这不是真正的Cursor资源ID）
        status->cursor_id = cursor_image->cursor_serial;
        
        printf("XFixes方法: 位置=(%d,%d), 序列号=%lu, 尺寸: %dx%d\n", 
               status->x, status->y, status->cursor_id, status->width, status->height);
        
        // 注意：我们不能使用cursor_serial来调用XFixesGetCursorName
        // 因为cursor_serial不是有效的Cursor资源ID
        
        status->is_visible = (cursor_image->width > 0 && cursor_image->height > 0);
        
        // 释放光标图像资源
        XFree(cursor_image);
    } else {
        fprintf(stderr, "XFixes方法: 无法获取光标图像\n");
        free_cursor_status(status);
        return NULL;
    }
    
    return status;
}

// 方法3：安全的资源获取方法
CursorStatus* get_cursor_status_safe(Display* display) {
    CursorStatus* status = malloc(sizeof(CursorStatus));
    if (!status) {
        fprintf(stderr, "内存分配失败\n");
        return NULL;
    }
    
    // 初始化
    memset(status, 0, sizeof(CursorStatus));
    status->cursor_name = strdup("未知");
    status->cursor_id = 0;
    
    Window root, child;
    int root_x, root_y, win_x, win_y;
    unsigned int mask;
    
    // 获取根窗口
    root = DefaultRootWindow(display);
    
    // 获取指针信息
    if (XQueryPointer(display, root, &root, &child, &root_x, &root_y, &win_x, &win_y, &mask)) {
        status->x = root_x;
        status->y = root_y;
        status->is_visible = 1;
        
        // 使用XFixes获取额外信息（如果可用）
        int event_base, error_base;
        if (XFixesQueryExtension(display, &event_base, &error_base)) {
            XFixesCursorImage* cursor_image = XFixesGetCursorImage(display);
            if (cursor_image) {
                status->width = cursor_image->width;
                status->height = cursor_image->height;
                status->cursor_id = cursor_image->cursor_serial;
                XFree(cursor_image);
                
                printf("安全方法: 位置=(%d,%d), 序列号=%lu, 尺寸=%dx%d\n",
                       status->x, status->y, status->cursor_id, status->width, status->height);
            }
        }
    } else {
        fprintf(stderr, "安全方法: 无法获取指针信息\n");
        free_cursor_status(status);
        return NULL;
    }
    
    return status;
}

// 全局变量，用于控制主循环
volatile sig_atomic_t running = 1;

// 信号处理函数
void signal_handler(int sig) {
    running = 0;
}

// 综合多种方法获取光标状态
CursorStatus* get_cursor_status(Display* display) {
    CursorStatus* status = NULL;
    
    // 优先尝试安全方法
    status = get_cursor_status_safe(display);
    if (status) {
        return status;
    }
    
    // 如果安全方法失败，尝试XFixes方法
    status = get_cursor_status_xfixes(display);
    if (status) {
        return status;
    }
    
    // 如果仍然失败，使用基本方法
    return get_cursor_status_basic(display);
}

int main() {
    Display* display = NULL;
    CursorStatus* status = NULL;
    CursorStatus* prev_status = NULL;
    
    // 打开X显示连接
    display = XOpenDisplay(NULL);
    if (!display) {
        fprintf(stderr, "无法打开X显示连接，请确保在X11环境中运行\n");
        return 1;
    }
    
    printf("光标状态监控器已启动（安全版本）\n");
    printf("提示: 移动鼠标、点击、拖拽等操作来观察鼠标状态变化\n");
    printf("按Ctrl+C退出程序\n\n");
    
    // 检查XFixes版本
    int event_base, error_base;
    if (XFixesQueryExtension(display, &event_base, &error_base)) {
        int major, minor;
        XFixesQueryVersion(display, &major, &minor);
        printf("XFixes扩展版本: %d.%d\n", major, minor);
    } else {
        printf("XFixes扩展不可用，部分功能受限\n");
    }
    
    // 设置错误处理程序来捕获X错误
    XSetErrorHandler(NULL);
    
    // 注册SIGINT信号处理函数
    signal(SIGINT, signal_handler);
    
    int iteration = 0;
    
    // 主循环
    while (running) {
        iteration++;
        
        // 获取当前光标状态
        status = get_cursor_status(display);
        
        if (status) {
            // 只有当状态变化时才打印
            int should_print = 0;
            
            if (!prev_status) {
                should_print = 1; // 第一次运行时打印
            } else if (prev_status->x != status->x || prev_status->y != status->y ||
                       prev_status->cursor_id != status->cursor_id) {
                should_print = 1; // 状态变化时打印
            }
            
            // 每50次迭代强制打印一次状态
            if (iteration % 50 == 0) {
                should_print = 1;
            }
            
            if (should_print) {
                printf("光标状态: 位置=(%d,%d), 序列号=%lu, 名称='%s', 尺寸=%dx%d, 可见=%s\n", 
                       status->x, status->y,
                       status->cursor_id,
                       status->cursor_name,
                       status->width, status->height,
                       status->is_visible ? "是" : "否");
                fflush(stdout);
            }
            
            // 清理前一个状态
            if (prev_status) {
                free_cursor_status(prev_status);
            }
            prev_status = status;
        } else {
            fprintf(stderr, "无法获取光标状态\n");
        }
        
        // 短暂延迟以减少CPU使用
        usleep(50000); // 50ms
    }
    
    // 清理资源
    if (prev_status) {
        free_cursor_status(prev_status);
    }
    
    if (display) {
        XCloseDisplay(display);
    }
    
    printf("\n程序已退出\n");
    return 0;
}